/*-------------------------------------------------------------------------
 * 用于处理嵌套条件的自动机状态堆栈。
 *
 * 此文件描述了一个自动机状态的堆栈，它允许管理嵌套条件。
 *
 * 它被以下内容使用：
 * - “psql”解释器用于处理\if ... \endif
 * - “pgbench”解释器用于处理\if ... \endif
 * - “pgbench”语法检查器测试正确的嵌套
 *
 * 堆栈保存包含条件的状态（我们处于真实分支中吗？在假分支中吗？我们是否已遇到真实分支？），
 * 以便解释器知道是否执行代码以及是否评估条件。
 *
 * Copyright (c) 2000-2022, PostgreSQL Global Development Group
 *
 * src/include/fe_utils/conditional.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef CONDITIONAL_H
#define CONDITIONAL_H

/*
 * 单个 \if 块的可能状态。
 */
typedef enum ifState
{
	IFSTATE_NONE = 0,			/* 当前不在 \if 块中 */
	IFSTATE_TRUE,				/* 当前在一个为真 \if 或 \elif 中，且所有父分支（如果有）均为真 */
	IFSTATE_FALSE,				/* 当前在一个为假 \if 或 \elif 中，但尚未看到任何为真分支，且所有父分支（如果有）均为真 */
	IFSTATE_IGNORED,			/* 当前在一个跟随为真分支的 \elif 中，或整个 \if 是一个为假父分支的子分支 */
	IFSTATE_ELSE_TRUE,			/* 当前在一个\else中，且所有
								 * 父分支（如有）都为真 */
	IFSTATE_ELSE_FALSE			/* 当前在一个\else中，且为假或
								 * 被忽略 */
} ifState;

/*
 * 嵌套\ifs的状态存储在栈中。
 *
 * query_len用于确定在非活动分支结束时要丢弃的累积文本。
 * （我们或许可以教lexer在进入非活动分支时就不向查询缓冲区添加
 * 内容；但那样会非常侵入性。）我们还需要在丢弃文本时保存和恢复
 * lexer的括号嵌套深度。（我们不需要保存和恢复其其他状态，例如注释
 * 嵌套深度，因为反斜杠命令不可能出现在注释或SQL字面量内部。）
 */
typedef struct IfStackElem
{
	ifState		if_state;		/* 当前状态，见上面的枚举 */
	int			query_len;		/* 上一个分支开始时query_buf的长度 */
	int			paren_depth;	/* 上一个分支开始时的括号深度 */
	struct IfStackElem *next;	/* 下一个周围的\if，如果有的话 */
} IfStackElem;

typedef struct ConditionalStackData
{
	IfStackElem *head;
}			ConditionalStackData;

typedef struct ConditionalStackData *ConditionalStack;


extern ConditionalStack conditional_stack_create(void);

extern void conditional_stack_reset(ConditionalStack cstack);

extern void conditional_stack_destroy(ConditionalStack cstack);

extern int	conditional_stack_depth(ConditionalStack cstack);

extern void conditional_stack_push(ConditionalStack cstack, ifState new_state);

extern bool conditional_stack_pop(ConditionalStack cstack);

extern ifState conditional_stack_peek(ConditionalStack cstack);

extern bool conditional_stack_poke(ConditionalStack cstack, ifState new_state);

extern bool conditional_stack_empty(ConditionalStack cstack);

extern bool conditional_active(ConditionalStack cstack);

extern void conditional_stack_set_query_len(ConditionalStack cstack, int len);

extern int	conditional_stack_get_query_len(ConditionalStack cstack);

extern void conditional_stack_set_paren_depth(ConditionalStack cstack, int depth);

extern int	conditional_stack_get_paren_depth(ConditionalStack cstack);

#endif							/* CONDITIONAL_H */
